package businessvariable

import (
	"errors"

	"github.com/grafana/grafana-foundation-sdk/go/cog"
	"github.com/grafana/grafana-foundation-sdk/go/dashboard"
)

var _ cog.Builder[dashboard.Panel] = (*PanelBuilder)(nil)

type PanelBuilder struct {
	internal *dashboard.Panel
	errors   map[string]cog.BuildErrors
}

func NewPanelBuilder() *PanelBuilder {
	resource := &dashboard.Panel{}
	builder := &PanelBuilder{
		internal: resource,
		errors:   make(map[string]cog.BuildErrors),
	}

	builder.applyDefaults()
	builder.internal.Type = "volkovlabs-variable-panel"

	return builder
}

func (builder *PanelBuilder) Build() (dashboard.Panel, error) {
	var errs cog.BuildErrors

	for _, err := range builder.errors {
		errs = append(errs, cog.MakeBuildErrors("Panel", err)...)
	}

	if len(errs) != 0 {
		return dashboard.Panel{}, errs
	}

	return *builder.internal, nil
}

// The version of the plugin that is used for this panel. This is used to find the plugin to display the panel and to migrate old panel configs.
func (builder *PanelBuilder) PluginVersion(pluginVersion string) *PanelBuilder {
	builder.internal.PluginVersion = &pluginVersion

	return builder
}

// Unique identifier of the panel. Generated by Grafana when creating a new panel. It must be unique within a dashboard, but not globally.
func (builder *PanelBuilder) Id(id uint32) *PanelBuilder {
	builder.internal.Id = &id

	return builder
}

// Panel title.
func (builder *PanelBuilder) Title(title string) *PanelBuilder {
	builder.internal.Title = &title

	return builder
}

// Panel description.
func (builder *PanelBuilder) Description(description string) *PanelBuilder {
	builder.internal.Description = &description

	return builder
}

// Whether to display the panel without a background.
func (builder *PanelBuilder) Transparent(transparent bool) *PanelBuilder {
	builder.internal.Transparent = &transparent

	return builder
}

// The datasource used in all targets.
func (builder *PanelBuilder) Datasource(datasource dashboard.DataSourceRef) *PanelBuilder {
	builder.internal.Datasource = &datasource

	return builder
}

// Grid position.
func (builder *PanelBuilder) GridPos(gridPos dashboard.GridPos) *PanelBuilder {
	builder.internal.GridPos = &gridPos

	return builder
}

// Panel height. The height is the number of rows from the top edge of the panel.
func (builder *PanelBuilder) Height(h uint32) *PanelBuilder {
	if !(h > 0) {
		builder.errors["h"] = cog.MakeBuildErrors("h", errors.New("h must be > 0"))
		return builder
	}
	if builder.internal.GridPos == nil {
		builder.internal.GridPos = &dashboard.GridPos{}
	}
	builder.internal.GridPos.H = h

	return builder
}

// Panel width. The width is the number of columns from the left edge of the panel.
func (builder *PanelBuilder) Span(w uint32) *PanelBuilder {
	if !(w > 0) {
		builder.errors["w"] = cog.MakeBuildErrors("w", errors.New("w must be > 0"))
		return builder
	}
	if !(w <= 24) {
		builder.errors["w"] = cog.MakeBuildErrors("w", errors.New("w must be <= 24"))
		return builder
	}
	if builder.internal.GridPos == nil {
		builder.internal.GridPos = &dashboard.GridPos{}
	}
	builder.internal.GridPos.W = w

	return builder
}

// Panel links.
func (builder *PanelBuilder) Links(links []cog.Builder[dashboard.DashboardLink]) *PanelBuilder {
	linksResources := make([]dashboard.DashboardLink, 0, len(links))
	for _, r1 := range links {
		linksDepth1, err := r1.Build()
		if err != nil {
			builder.errors["links"] = err.(cog.BuildErrors)
			return builder
		}
		linksResources = append(linksResources, linksDepth1)
	}
	builder.internal.Links = linksResources

	return builder
}

// Name of template variable to repeat for.
func (builder *PanelBuilder) Repeat(repeat string) *PanelBuilder {
	builder.internal.Repeat = &repeat

	return builder
}

// Direction to repeat in if 'repeat' is set.
// `h` for horizontal, `v` for vertical.
func (builder *PanelBuilder) RepeatDirection(repeatDirection dashboard.PanelRepeatDirection) *PanelBuilder {
	builder.internal.RepeatDirection = &repeatDirection

	return builder
}

// Option for repeated panels that controls max items per row
// Only relevant for horizontally repeated panels
func (builder *PanelBuilder) MaxPerRow(maxPerRow float64) *PanelBuilder {
	builder.internal.MaxPerRow = &maxPerRow

	return builder
}

func (builder *PanelBuilder) DisplayMode(displayMode DisplayMode) *PanelBuilder {
	if builder.internal.Options == nil {
		builder.internal.Options = &Options{}
	}
	builder.internal.Options.(*Options).DisplayMode = displayMode

	return builder
}

func (builder *PanelBuilder) Padding(padding int) *PanelBuilder {
	if builder.internal.Options == nil {
		builder.internal.Options = &Options{}
	}
	builder.internal.Options.(*Options).Padding = padding

	return builder
}

func (builder *PanelBuilder) ShowLabel(showLabel bool) *PanelBuilder {
	if builder.internal.Options == nil {
		builder.internal.Options = &Options{}
	}
	builder.internal.Options.(*Options).ShowLabel = showLabel

	return builder
}

func (builder *PanelBuilder) Variable(variable string) *PanelBuilder {
	if builder.internal.Options == nil {
		builder.internal.Options = &Options{}
	}
	builder.internal.Options.(*Options).Variable = variable

	return builder
}

func (builder *PanelBuilder) applyDefaults() {
	builder.PluginVersion("3.7.0")
	builder.Height(8)
	builder.Span(12)
	builder.DisplayMode(DisplayModeTable)
}
